package com.devbobcorn.nekoration.client.rendering.blockentities;

import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import com.devbobcorn.nekoration.Nekoration;
import com.devbobcorn.nekoration.blocks.entities.PhonographBlockEntity;
import com.devbobcorn.nekoration.client.rendering.MusicRenderer;
import com.devbobcorn.nekoration.client.rendering.RenderTypeHelper;
import com.devbobcorn.nekoration.sounds.music.VisualHelper;
import com.google.common.collect.ImmutableList;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;

import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Matrix4f;

public class PhonographRenderer extends TileEntityRenderer<PhonographBlockEntity> {
	public static final ResourceLocation CAT_SKY = new ResourceLocation(Nekoration.MODID, "textures/misc/cat_sky.png");
	public static final ResourceLocation CAT_PORTAL = new ResourceLocation(Nekoration.MODID, "textures/misc/cat_portal.png");

	private static final Random RANDOM = new Random(31100L);
	private static final List<RenderType> RENDER_TYPES = IntStream.range(0, 16).mapToObj((layer) -> {
		return RenderTypeHelper.catPortal(layer + 1);
	}).collect(ImmutableList.toImmutableList());

	public PhonographRenderer(TileEntityRendererDispatcher tileEntityRendererDispatcher) {
		super(tileEntityRendererDispatcher);
	}

	public void render(PhonographBlockEntity tileEntity, float partialTicks, MatrixStack stack, IRenderTypeBuffer buffers, int combinedLight, int combinedOverlay) {
		RANDOM.setSeed(31100L);
		double d0 = tileEntity.getBlockPos().distSqr(this.renderer.camera.getPosition(), true);
		int layerCnt = this.getPasses(d0);
		Matrix4f matrix4f = stack.last().pose();
		// Render the background...
		float r = 1.0F;
		float g = 1.0F;
		float b = 1.0F;
		this.renderCube(tileEntity, 1.0F, r, g, b, matrix4f, buffers.getBuffer(RENDER_TYPES.get(0)));
		// Render the stars...
		for (int j = 1; j < layerCnt; ++j) {
			float color = 2.0F / (float) (18 - j);
			r = (RANDOM.nextFloat() * 0.5F + 0.1F) * color;
			g = (RANDOM.nextFloat() * 0.5F + 0.4F) * color;
			b = (RANDOM.nextFloat() * 0.5F + 0.5F) * color;
			this.renderCube(tileEntity, 1.0F, r, g, b, matrix4f, buffers.getBuffer(RENDER_TYPES.get(j)));
		}
		MusicRenderer.render(tileEntity, partialTicks, stack, buffers, combinedLight, combinedOverlay);
		final double radius = 42.0;
		for (int idx = 0; idx < VisualHelper.BAR_NUM; idx++){
			double offset = VisualHelper.buffer[idx] / 16.0 + 8.0;
			double frac = idx / (double) VisualHelper.BAR_NUM;
			double offsetZ = -radius * Math.sin(Math.PI * frac);
			double offsetX = radius * Math.cos(Math.PI * frac);
			stack.translate(offsetX, 0.0, offsetZ);
			// Render the notes...
			r = g = b = 1.0F;
			this.renderCube(tileEntity, (float)offset, r, g, b, stack.last().pose(), buffers.getBuffer(RENDER_TYPES.get(0)));
			stack.translate(-offsetX, 0.0, -offsetZ);
		}
	}

	private void renderCube(PhonographBlockEntity tileEntity, float hght, float r, float g, float b, Matrix4f pose, IVertexBuilder vertexBuilder) {
		float gap = 0.125F;
		this.renderFace(tileEntity, pose, vertexBuilder, 0.0F + gap, 1.0F - gap, 0.0F + gap, hght - gap, 1.0F - gap, 1.0F - gap, 1.0F - gap, 1.0F - gap, r, g, b, Direction.SOUTH);
		this.renderFace(tileEntity, pose, vertexBuilder, 0.0F + gap, 1.0F - gap, hght - gap, 0.0F + gap, 0.0F + gap, 0.0F + gap, 0.0F + gap, 0.0F + gap, r, g, b, Direction.NORTH);
		this.renderFace(tileEntity, pose, vertexBuilder, 1.0F - gap, 1.0F - gap, hght - gap, 0.0F + gap, 0.0F + gap, 1.0F - gap, 1.0F - gap, 0.0F + gap, r, g, b, Direction.EAST);
		this.renderFace(tileEntity, pose, vertexBuilder, 0.0F + gap, 0.0F + gap, 0.0F + gap, hght - gap, 0.0F + gap, 1.0F - gap, 1.0F - gap, 0.0F + gap, r, g, b, Direction.WEST);
		this.renderFace(tileEntity, pose, vertexBuilder, 0.0F + gap, 1.0F - gap, 0.0F + gap, 0.0F + gap, 0.0F + gap, 0.0F + gap, 1.0F - gap, 1.0F - gap, r, g, b, Direction.DOWN);
		this.renderFace(tileEntity, pose, vertexBuilder, 0.0F + gap, 1.0F - gap, hght - gap, hght - gap, 1.0F - gap, 1.0F - gap, 0.0F + gap, 0.0F + gap, r, g, b, Direction.UP);
	}

	private void renderFace(PhonographBlockEntity tileEntity, Matrix4f pose, IVertexBuilder vertexBuilder, float x1, float x2, float y1, float y2, float z1, float z2, float z3, float z4, float r, float g, float b, Direction dir) {
		if (tileEntity.shouldRenderFace(dir)) {
			vertexBuilder.vertex(pose, x1, y1, z1).color(r, g, b, 1.0F).endVertex();
			vertexBuilder.vertex(pose, x2, y1, z2).color(r, g, b, 1.0F).endVertex();
			vertexBuilder.vertex(pose, x2, y2, z3).color(r, g, b, 1.0F).endVertex();
			vertexBuilder.vertex(pose, x1, y2, z4).color(r, g, b, 1.0F).endVertex();
		}
	}

	protected int getPasses(double sqrDist) {
		if (sqrDist > 36864.0D) {
			return 1;
		} else if (sqrDist > 25600.0D) {
			return 3;
		} else if (sqrDist > 16384.0D) {
			return 5;
		} else if (sqrDist > 9216.0D) {
			return 7;
		} else if (sqrDist > 4096.0D) {
			return 9;
		} else if (sqrDist > 1024.0D) {
			return 11;
		} else if (sqrDist > 576.0D) {
			return 13;
		} else {
			return sqrDist > 256.0D ? 14 : 15;
		}
	}

	public boolean shouldRenderOffScreen(PhonographBlockEntity tileEntity) {
		return true;
	}
}
